﻿using SDFL.Core.DataStructure;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using System.Reflection;
namespace Test_SDFL_GeneralFunc
{
    public class People
    {
        public string Name
        {
            get;
            set;
        }

        public string Sex
        {
            get;
            set;
        }

        public People()
        {            
            this.Name = "NoName";
            this.Sex = "None";
        }

        public People(string name, string sex)
        {
            this.Name = name;
            this.Sex = sex;
        }

        public override string ToString()
        {
            string tempStr = string.Format("Name is {0}; Sex is {1}", this.Name, this.Sex);
            return tempStr;
        }
    }
    
    
    /// <summary>
    ///This is a test class for LinkedListTest and is intended
    ///to contain all LinkedListTest Unit Tests
    ///</summary>
    [TestClass()]
    public class LinkedListTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for Item
        ///</summary>
        public void ItemTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> target = new LinkedList<K, T>(); // TODO: Initialize to an appropriate value
            //K key = new K(); // TODO: Initialize to an appropriate value
            //T actual;
            //actual = target[key];
            //Assert.Inconclusive("Verify the correctness of this test method.");
        }

        [TestMethod()]
        public void ItemTest()
        {
            LinkedList<int, People> target = new LinkedList<int, People>();

            target.AddHead(123, new People("Dylan Wang", "Man"));
            target.AddHead(456, new People("Sally Pan", "Woman"));

            string actual = target[456].Name;
            Assert.AreEqual("Sally Pan", actual);
        }

        /// <summary>
        ///A test for Head
        ///</summary>
        public void HeadTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> target = new LinkedList<K, T>(); // TODO: Initialize to an appropriate value
            //Node<K, T> actual;
            //actual = target.Head;
            //Assert.Inconclusive("Verify the correctness of this test method.");
        }

        [TestMethod()]
        public void HeadTest()
        {
            LinkedList<int, People> target1 = new LinkedList<int, People>();
            target1.AddHead(11, new People("Dylan Wang", "Man"));
            target1.AddHead(22, new People("Sally Pan", "Woman"));

            Assert.AreEqual("Sally Pan", target1.Head.NextNode.m_Item.Name);            
        }

        /// <summary>
        ///A test for op_Addition
        ///</summary>
        public void op_AdditionTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> lhs = null; // TODO: Initialize to an appropriate value
            //LinkedList<K, T> rhs = null; // TODO: Initialize to an appropriate value
            //LinkedList<K, T> expected = null; // TODO: Initialize to an appropriate value
            //LinkedList<K, T> actual;
            //actual = (lhs + rhs);
            //Assert.AreEqual(expected, actual);
            //Assert.Inconclusive("Verify the correctness of this test method.");
        }

        [TestMethod()]
        public void op_AdditionTest()
        {
            LinkedList<int, People> target1 = new LinkedList<int, People>();
            target1.AddHead(11, new People("Dylan Wang", "Man"));
            target1.AddHead(22, new People("Sally Pan", "Woman"));

            LinkedList<int, People> target2 = new LinkedList<int, People>();
            target2.AddHead(33, new People("Jack Du", "Man"));
            target2.AddHead(44, new People("Mary Huang", "Woman"));

            LinkedList<int, People> actual = new LinkedList<int, People>();
            actual = target1 + target2;

            LinkedList<int, People> expected = new LinkedList<int,People>();
            expected.AddHead(33, new People("Jack Du", "Man"));
            expected.AddHead(44, new People("Mary Huang", "Woman"));
            expected.AddHead(11, new People("Dylan Wang", "Man"));
            expected.AddHead(22, new People("Sally Pan", "Woman"));
            
            Assert.AreEqual<LinkedList<int, People>>(expected, actual);                        
        }

        /// <summary>
        ///A test for Find
        ///</summary>
        public void FindTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> target = new LinkedList<K, T>(); // TODO: Initialize to an appropriate value
            //K key = new K(); // TODO: Initialize to an appropriate value
            //T expected = new T(); // TODO: Initialize to an appropriate value
            //T actual;
            //actual = target.Find(key);
            //Assert.AreEqual(expected, actual);
            //Assert.Inconclusive("Verify the correctness of this test method.");
        }

        [TestMethod()]
        public void FindTest()
        {
            LinkedList<int, People> target = new LinkedList<int, People>();

            target.AddHead(123, new People("Dylan Wang", "Man"));
            target.AddHead(456, new People("Sally Pan", "Woman"));

            string actual = target.Find(456).Name;
            Assert.AreEqual("Sally Pan", actual);
        }

        /// <summary>
        ///A test for concatenate
        ///</summary>
        public void concatenateTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> list1 = null; // TODO: Initialize to an appropriate value
            //LinkedList<K, T> list2 = null; // TODO: Initialize to an appropriate value
            //LinkedList<K, T> expected = null; // TODO: Initialize to an appropriate value
            //LinkedList<K, T> actual;
            //actual = LinkedList_Accessor<K, T>.concatenate(list1, list2);
            //Assert.AreEqual(expected, actual);
            //Assert.Inconclusive("Verify the correctness of this test method.");
        }               

        /// <summary>
        ///A test for AddLast
        ///</summary>
        public void AddLastTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> target = new LinkedList<K, T>(); // TODO: Initialize to an appropriate value
            //K key = new K(); // TODO: Initialize to an appropriate value
            //T item = new T(); // TODO: Initialize to an appropriate value
            //target.AddLast(key, item);
            //Assert.Inconclusive("A method that does not return a value cannot be verified.");
        }

        [TestMethod()]
        public void AddLastTest()
        {
            LinkedList<int, People> target1 = new LinkedList<int, People>();
            target1.AddHead(11, new People("Dylan Wang", "Man"));
            target1.AddHead(22, new People("Sally Pan", "Woman"));
            target1.AddLast(33, new People("Jack Du", "man"));
            Assert.AreEqual("Jack Du", target1.Head.NextNode.NextNode.NextNode.m_Item.Name);

            LinkedList<int, People> target2 = new LinkedList<int, People>();            
            target2.AddLast(33, new People("Jack Du", "man"));
            Assert.AreEqual("Jack Du", target2.Head.NextNode.m_Item.Name);
        }

        /// <summary>
        ///A test for AddHead
        ///</summary>
        public void AddHeadTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> target = new LinkedList<K, T>(); // TODO: Initialize to an appropriate value
            //K key = new K(); // TODO: Initialize to an appropriate value
            //T item = new T(); // TODO: Initialize to an appropriate value
            //target.AddHead(key, item);
            //Assert.Inconclusive("A method that does not return a value cannot be verified.");
        }

        [TestMethod()]
        public void AddHeadTest()
        {
            LinkedList<int, People> target1 = new LinkedList<int, People>();
            target1.AddHead(11, new People("Dylan Wang", "Man"));
            target1.AddHead(22, new People("Sally Pan", "Woman"));

            Assert.AreEqual("Sally Pan", target1.Head.NextNode.m_Item.Name);  
        }

        /// <summary>
        ///A test for LinkedList`2 Constructor
        ///</summary>
        public void LinkedListConstructorTestHelper<K, T>()
            where K : struct
            where T : new()
        {
            //LinkedList<K, T> target = new LinkedList<K, T>();
            //Assert.Inconclusive("TODO: Implement code to verify target");
        }

        /// <summary>
        /// Generic reflection
        /// </summary>
        [TestMethod()]
        public void LinkedListConstructorTest()
        {
            LinkedList<int, People> c = new LinkedList<int, People>();
            Type myType = c.GetType();
            Trace.WriteLine(c.ToString());
            //SDFL.Core.DataStructure.LinkedList`2[System.Int32,Test_SDFL_GeneralFunc.People]

            Assert.IsTrue(myType.IsGenericType);
            
            Type[] parameters = myType.GetGenericArguments();
            Assert.AreEqual(2, parameters.Length);
            Assert.AreEqual(typeof(int), parameters[0]);
            Assert.AreEqual(typeof(People), parameters[1]);

            Type myTypeDef = myType.GetGenericTypeDefinition();
            Assert.AreEqual(typeof(LinkedList<,>), myTypeDef);
            Trace.WriteLine(myTypeDef.ToString());
            //SDFL.Core.DataStructure.LinkedList`2[K,T]

            // generic reflection's method caller
            LinkedList<int, People> d = new LinkedList<int, People>();
            Type dType = d.GetType();
            MethodInfo addHeadmethod = dType.GetMethod("AddHead");
            object[] paras = { 1, new People("wang", "man") };
            addHeadmethod.Invoke(d, paras);
            Assert.AreEqual("wang", d.Head.NextNode.m_Item.Name);
        }
    }
}
